package com.example.memento.download.service;

import com.example.memento.download.model.IpGeoInfo;
import com.example.memento.download.util.IpUtils;
import com.maxmind.geoip2.DatabaseReader;
import com.maxmind.geoip2.model.CityResponse;
import lombok.extern.slf4j.Slf4j;
import org.lionsoul.ip2region.xdb.Searcher;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import java.io.InputStream;
import java.net.InetAddress;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Optional;

/**
 * IP 地址地理位置识别服务
 * 支持 GeoLite2-City.mmdb 和 ip2region.xdb 两种数据源
 */
@Slf4j
@Service
public class IpGeoService {
    
    private static final String GEOLITE2_RESOURCE = "geo/GeoLite2-City.mmdb";
    private static final String IP2REGION_RESOURCE = "ipdb/ip2region.xdb";
    
    private DatabaseReader geoLiteReader;
    private Searcher ip2RegionSearcher;
    private Path ip2RegionTempFile;
    
    @PostConstruct
    public void init() {
        // 初始化 GeoLite2 数据库
        initGeoLite2();
        
        // 初始化 ip2region 数据库
        initIp2Region();
    }
    
    private void initGeoLite2() {
        try {
            ClassPathResource resource = new ClassPathResource(GEOLITE2_RESOURCE);
            if (!resource.exists()) {
                log.warn("GeoLite2-City.mmdb 文件不存在，跳过初始化");
                return;
            }
            
            try (InputStream inputStream = resource.getInputStream()) {
                geoLiteReader = new DatabaseReader.Builder(inputStream).build();
                log.info("GeoLite2-City.mmdb 初始化成功，版本: {}", geoLiteReader.getMetadata().getDatabaseType());
            }
        } catch (Exception e) {
            log.error("初始化 GeoLite2 数据库失败", e);
        }
    }
    
    private void initIp2Region() {
        try {
            ClassPathResource resource = new ClassPathResource(IP2REGION_RESOURCE);
            if (!resource.exists()) {
                log.warn("ip2region.xdb 文件不存在，跳过初始化");
                return;
            }
            
            // ip2region 需要文件路径，不能直接使用 InputStream，先复制到临时文件
            ip2RegionTempFile = Files.createTempFile("ip2region-", ".xdb");
            try (InputStream inputStream = resource.getInputStream()) {
                Files.copy(inputStream, ip2RegionTempFile, StandardCopyOption.REPLACE_EXISTING);
            }
            
            ip2RegionSearcher = Searcher.newWithFileOnly(ip2RegionTempFile.toString());
            log.info("ip2region.xdb 初始化成功");
        } catch (Exception e) {
            log.error("初始化 ip2region 数据库失败", e);
        }
    }
    
    /**
     * 获取 IP 地址地理位置信息
     * 优先级：GeoLite2 > ip2region > 远程 API
     */
    public IpGeoInfo getGeoInfo(String ip) {
        if (ip == null || ip.isEmpty() || !IpUtils.isValidIP(ip)) {
            return null;
        }
        
        // 内网 IP 返回 null
        if (IpUtils.isInternalIP(ip)) {
            log.debug("内网 IP: {}", ip);
            return null;
        }
        
        // 尝试使用 GeoLite2 查询
        IpGeoInfo info = queryByGeoLite2(ip);
        if (info != null) {
            return info;
        }
        
        // 尝试使用 ip2region 查询
        info = queryByIp2Region(ip);
        if (info != null) {
            return info;
        }
        
        // 最后尝试远程 API（可选实现）
        // info = queryByRemoteApi(ip);
        
        return null;
    }
    
    /**
     * 使用 GeoLite2 数据库查询
     */
    private IpGeoInfo queryByGeoLite2(String ip) {
        if (geoLiteReader == null) {
            return null;
        }
        
        try {
            InetAddress ipAddress = InetAddress.getByName(ip);
            CityResponse response = geoLiteReader.city(ipAddress);
            
            return IpGeoInfo.builder()
                    .countryCode(Optional.ofNullable(response.getCountry().getIsoCode()).orElse(""))
                    .country(Optional.ofNullable(response.getCountry().getName()).orElse(""))
                    .region(Optional.ofNullable(response.getLeastSpecificSubdivision())
                            .map(s -> s.getName()).orElse(""))
                    .city(Optional.ofNullable(response.getCity()).map(c -> c.getName()).orElse(""))
                    .source("GeoLite2")
                    .build();
        } catch (Exception e) {
            log.debug("GeoLite2 查询失败，IP={}, error={}", ip, e.getMessage());
            return null;
        }
    }
    
    /**
     * 使用 ip2region 数据库查询
     */
    private IpGeoInfo queryByIp2Region(String ip) {
        if (ip2RegionSearcher == null) {
            return null;
        }
        
        try {
            String region = ip2RegionSearcher.search(ip);
            if (region == null || region.isEmpty()) {
                return null;
            }
            
            // ip2region 返回格式：国家|区域|省份|城市|ISP
            String[] parts = region.split("\\|");
            if (parts.length < 5) {
                return null;
            }
            
            String country = parts[0];
            String regionName = parts[1];
            String province = parts[2];
            String city = parts[3];
            // String isp = parts[4]; // ISP 信息暂不使用
            
            // 处理 ip2region 的特殊值
            if ("0".equals(country)) country = "";
            if ("0".equals(regionName)) regionName = "";
            if ("0".equals(province)) province = "";
            if ("0".equals(city)) city = "";
            
            StringBuilder address = new StringBuilder();
            if (!country.isEmpty()) address.append(country);
            if (!province.isEmpty()) {
                if (address.length() > 0) address.append(" ");
                address.append(province);
            }
            if (!city.isEmpty()) {
                if (address.length() > 0) address.append(" ");
                address.append(city);
            }
            
            return IpGeoInfo.builder()
                    .country(country)
                    .region(province.isEmpty() ? regionName : province)
                    .city(city)
                    .address(address.toString())
                    .source("ip2region")
                    .build();
        } catch (Exception e) {
            log.debug("ip2region 查询失败，IP={}, error={}", ip, e.getMessage());
            return null;
        }
    }
    
    @PreDestroy
    public void destroy() {
        try {
            if (geoLiteReader != null) {
                geoLiteReader.close();
            }
        } catch (Exception e) {
            log.warn("关闭 GeoLite2 数据库失败", e);
        }
        
        try {
            if (ip2RegionSearcher != null) {
                ip2RegionSearcher.close();
            }
        } catch (Exception e) {
            log.warn("关闭 ip2region 搜索器失败", e);
        }
        
        try {
            if (ip2RegionTempFile != null) {
                Files.deleteIfExists(ip2RegionTempFile);
            }
        } catch (Exception e) {
            log.warn("删除临时文件失败", e);
        }
    }
}

